import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Loading and Running Yarn Scripts

Welcome to the YarnRunner library usage tutorial. In this guide, we'll show you how to load and run the Yarn narrative script you wrote in the [previous tutorial](/docs/tutorial/Writing%20Game%20Dialogue/introduction-to-yarn).

## 1. Initializing YarnRunner

<Tabs groupId="language-select">
<TabItem value="lua" label="Lua">

First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:

```lua title="init.lua"
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
```

To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:

```lua title="init.lua"
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
```

Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:

```lua title="init.lua"
local runner = YarnRunner("tutorial.yarn", "Start")
```

</TabItem>
<TabItem value="tl" label="Teal">

First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:

```tl title="init.tl"
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
```

To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:

```tl title="init.tl"
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
```

Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:

```tl title="init.tl"
local runner = YarnRunner("tutorial.yarn", "Start")
```

</TabItem>
<TabItem value="ts" label="TypeScript">

First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:

```ts title="init.ts"
import { Content, Path, Node, Director } from "Dora";
import * as YarnRunner from "YarnRunner";
```

To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:

```ts title="init.ts"
const path = Path.getScriptPath(...);
Content.insertSearchPath(1, path);
```

Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:

```ts title="init.ts"
const runner = YarnRunner("tutorial.yarn", "Start");
```

</TabItem>
<TabItem value="yue" label="YueScript">

First, make sure you have imported all the necessary modules.

```yue title="init.yue"
_ENV = Dora
import "YarnRunner"
```

To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:

```yue title="init.yue"
path = Path\getScriptPath ...
Content\insertSearchPath 1, path
```

Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:

```yue title="init.yue"
runner = YarnRunner "tutorial.yarn", "Start"
```

</TabItem>
</Tabs>

## 2. Executing and Displaying Narrative Content

We define an `advance` function that can read and display text or options from the Yarn script. Based on the content, it can also display the character's name:

<Tabs groupId="language-select">
<TabItem value="lua" label="Lua">

```lua title="init.lua"
-- The advance function takes an optional integer representing the player's choice index.
-- For the first call or when no choice is needed, we pass nil.
local function advance(option)

	-- First, we call runner:advance(option) to get the next part of the Yarn script.
	-- This returns two values: an action type and a result.
	local action, result = runner:advance(option)

	-- Handle the result based on the action type.
	if action == "Text" then

		-- If the action is "Text", the result will be a TextResult object,
		-- containing the text and any associated markers (e.g., character names).
		-- Check the markers, extract the character's name (if present), and print the text.
		local characterName = ""
		local marks = result.marks
		if marks then
			for i = 1, #marks do
				local mark = marks[i]
				if mark.name == "char" then
					characterName = mark.attrs.name .. ": "
				end
			end
		end
		print(characterName .. result.text)

	elseif action == "Option" then

		-- If the action is "Option", the result will be an OptionResult object,
		-- containing one or more options. Iterate over the options and print them,
		-- allowing the player to select them later.
		for i, op in ipairs(result) do
			if op then
				print("[" .. tostring(i) .. "]: " .. op.text)
			end
		end

	else

		-- For other actions (like errors), print the result directly.
		print(result)

	end
end
```

</TabItem>
<TabItem value="tl" label="Teal">

```tl title="init.tl"
-- The advance function takes an optional integer representing the player's choice index.
-- For the first call or when no choice is needed, we pass nil.
local function advance(option?: integer)

	-- First, we call runner:advance(option) to get the next part of the Yarn script.
	-- This returns two values: an action type and a result.
	local action, result = runner:advance(option)

	-- Handle the result based on the action type.
	if action == "Text" then

		-- If the action is "Text", the result will be a TextResult object,
		-- containing the text and any associated markers (e.g., character names).
		local textResult = result as YarnRunner.TextResult

		-- Check the markers, extract the character's name (if present), and print the text.
		local characterName = ""
		local marks = textResult.marks
		if not (marks is nil) then
			for i = 1, #marks do
				local mark = marks[i]
				if mark.name == "char" then
					characterName = tostring(mark.attrs.name) .. ": "
				end
			end
		end
		print(characterName .. textResult.text)

	elseif action == "Option" then

		-- If the action is "Option", the result will be an OptionResult object,
		-- containing one or more options. Iterate over the options and print them,
		-- allowing the player to select them later.
		local optionResult = result as YarnRunner.OptionResult
		for i, op in ipairs(optionResult) do
			if op and not (op is boolean) then
				print("[" .. tostring(i) .. "]: " .. op.text)
			end
		end

	else

		-- For other actions (like errors), print the result directly.
		print(result)

	end
end
```

</TabItem>
<TabItem value="ts" label="TypeScript">

```ts title="init.ts"
// The advance function takes an optional integer representing the player's choice index.
// For the first call or when no choice is needed, we pass null.
function advance(option?: number): void {

	// First, we call runner.advance(option) to get the next part of the Yarn script.
	// This returns two values: an action type and a result.
	const [action, result] = runner.advance(option);

	// Handle the result based on the action type.
	switch (action) {
		case "Text":

			// If the action is "Text", the result will be a TextResult object,
			// containing the text and any associated markers (e.g., character names).
			// Check the markers, extract the character's name (if present), and print the text.
			let characterName = "";
			const marks = result.marks;
			if (marks) {
				for (const mark of marks) {


	if (mark.name === "char") {
						characterName = `${mark.attrs?.name}: `;
					}
				}
			}
			print(characterName + result.text);
			break;

		case "Option":

			// If the action is "Option", the result will be an OptionResult object,
			// containing one or more options. Iterate over the options and print them,
			// allowing the player to select them later.
			const optionResult = result;
			for (let i = 0; i < optionResult.length; i++) {
				const op = optionResult[i];
				if (op && op !== true) {
					print(`[${i}]: ${op.text}`);
				}
			}
			break;

		default:

			// For other actions (like errors), print the result directly.
			print(result);
			break;
	}
}
```

</TabItem>
<TabItem value="yue" label="YueScript">

```yue title="init.yue"
-- The advance function takes an optional integer representing the player's choice index.
-- For the first call or when no choice is needed, we pass nil.
advance = (option) ->

	-- First, call runner\advance to get the next part of the Yarn script.
	-- This returns two values: an action type and a result.
	action, result = runner\advance option

	-- Handle the result based on the action type.
	switch action when "Text"

		-- If the action is "Text", the result will be a TextResult object,
		-- containing the text and any associated markers (e.g., character names).
		-- Check the markers, extract the character's name (if present), and print the text.
		charName = ""
		if result.marks
			for mark in *result.marks
				switch mark when {name: attr, attrs: {:name}}
					charName = "#{name}: " if attr == "char"
		print charName .. result.text

	when "Option"

		-- If the action is "Option", the result will be an OptionResult object,
		-- containing one or more options. Iterate over the options and print them,
		-- allowing the player to select them later.
		for i, op in ipairs result
			print "[#{i}]: #{op.text}" if op

	else

		-- For other actions (like errors), print the result directly.
		print result
```

</TabItem>
</Tabs>

## 3. Starting the Narrative

To start the narrative, simply call the `advance` function without any arguments:

<Tabs groupId="language-select">
<TabItem value="lua" label="Lua">

```lua title="init.lua"
advance()
```

</TabItem>
<TabItem value="tl" label="Teal">

```tl title="init.tl"
advance()
```

</TabItem>
<TabItem value="ts" label="TypeScript">

```ts title="init.ts"
advance();
```

</TabItem>
<TabItem value="yue" label="YueScript">

```yue title="init.yue"
advance!
```

</TabItem>
</Tabs>

## 4. Handling User Input

To enable player interaction, we need a node to capture and respond to user input. We create a node and assign it a signal slot named "go". When this signal is triggered, it will call the `advance` function again, passing the player's choice:

<Tabs groupId="language-select">
<TabItem value="lua" label="Lua">

```lua title="init.lua"
local node = Node()
node:gslot("go", function(option)
	advance(option)
end)
node:addTo(Director.entry)
```

</TabItem>
<TabItem value="tl" label="Teal">

```tl title="init.tl"
local node = Node()
node:gslot("go", function(option: nil | integer)
	advance(option)
end)
node:addTo(Director.entry)
```

</TabItem>
<TabItem value="ts" label="TypeScript">

```ts title="init.ts"
const node = Node();
node.gslot("go", (option: number | null) => {
	advance(option);
});
node.addTo(Director.entry);
```

</TabItem>
<TabItem value="yue" label="YueScript">

```yue title="init.yue"
with Node!
	\gslot "go", (option) -> advance option
	\addTo Director.entry
```

</TabItem>
</Tabs>

Here, we registered a global event listener for quick testing. In actual game development, you'd need to write the UI interaction logic. Once this "go" global event listener is set, you can use the Dora SSR console to input `emit 'go'` to continue the dialogue, or `emit 'go', 1` to select dialogue branches for interactive test runs.

## 5. Adding Custom Commands and State

You can add custom commands and initial state variables by passing the `command` and `state` parameters to `YarnRunner`. The `command` parameter is a Lua table containing callback functions for commands, and `state` is a table with predefined variables. Here's an example:

<Tabs groupId="language-select">
<TabItem value="lua" label="Lua">

```lua title="init.lua"
local runner = YarnRunner("tutorial.yarn", "Start", {
	playerScore = 100
}, {
	print = print
})
```

</TabItem>
<TabItem value="tl" label="Teal">

```tl title="init.tl"
local runner = YarnRunner("tutorial.yarn", "Start", {
	playerScore = 100
}, {
	print = print
})
```

</TabItem>
<TabItem value="ts" label="TypeScript">

```ts title="init.ts"
const runner = YarnRunner("tutorial.yarn", "Start", {
	playerScore: 100
}, {
	print: print
})
```

</TabItem>
<TabItem value="yue" label="YueScript">

```yue title="init.yue"
runner = YarnRunner "tutorial.yarn", "Start", {
	playerScore: 100
}, {
	print: print
}
```

</TabItem>
</Tabs>

Then, in the Yarn script, you can modify initial variable values using `<<set $variable = expression>>` and print variables using the custom command `<<print $variable>>`:

```html title="Test Dialogue Node"
<<set $playerScore = $playerScore + 200>>
<<print $playerScore>>
```

## 6. Conclusion

Now, you have set up all the necessary code to load and run Yarn narrative scripts. You can run the above script to begin your interactive narrative, where players can interact by selecting options. Happy creating!
